package com.xncoding.aop.aspect.spel;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xncoding.aop.annotation.spel.OperationLogAnnotation;
import com.xncoding.aop.model.CompanyDTO;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.eclipse.jetty.util.StringUtil;
import org.springframework.context.expression.AnnotatedElementKey;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

@Component
@Aspect
@Slf4j
public class OperationLogAspect  {
    private static final ExpressionEvaluator<String> EVALUATOR = new ExpressionEvaluator<>();


    /**
     * 被执行方法上添加OperationLogAnnotation注解的才会执行这个方法
     * @param joinPoint
     */
    @AfterReturning(pointcut = "@annotation(com.xncoding.aop.annotation.spel.OperationLogAnnotation)", returning = "jsonObeject")
    public void doAfterReturning (JoinPoint joinPoint, JSONObject jsonObeject) {
        handleOperationLog(joinPoint, jsonObeject);
    }

    /**
     * 操作日志处理逻辑，包括：格式处理，持久化
     * @param joinPoint
     * @param jsonResult 返回结果
     */
    protected void handleOperationLog(final JoinPoint joinPoint, JSONObject jsonResult) {

        OperationLogAnnotation operationLogAnnotation = ((MethodSignature) joinPoint.getSignature()).getMethod().
                getAnnotation(OperationLogAnnotation.class);

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 获取方法名
        String methodName = joinPoint.getSignature().getName().toLowerCase();
        // 获取类名
        String className = joinPoint.getTarget().getClass().getName().toLowerCase();
        // 获取方法签名
        MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
        // 参数名称列表
        String[] parameterNames = methodSignature.getParameterNames();
        // content的默认值为返回结果
        String content = new String();
        Object[] args = joinPoint.getArgs();

        // 获取operationLogAnnotation注解的的content内容
        if (StringUtil.isNotBlank(operationLogAnnotation.content())) {
            // 解析EL表达式
            content = this.evalExpression(joinPoint, operationLogAnnotation.content() );
//            log.info("expression:{}", content);
        }


    }

    /**
     * 解析EL表达式
     * @param point 切入点
     * @param expression 需要解析的EL表达式
     * @return 解析出的值
     */
    private String evalExpression(JoinPoint point, String expression) {
        MethodSignature ms = (MethodSignature) point.getSignature();
        Method method = ms.getMethod();
        Object[] args = point.getArgs();
        Object target = point.getTarget();
        Class<?> targetClass = target.getClass();
        EvaluationContext context = EVALUATOR.createEvaluationContext(target, target.getClass(), method, args);
        AnnotatedElementKey elementKey = new AnnotatedElementKey(method, targetClass);

        return EVALUATOR.condition(expression, elementKey, context, String.class);
    }

    public static void main(String[] args) {
        /*CompanyDTO companyDTO = new CompanyDTO();
        companyDTO.setCompanyName("elqqqqqTest");
        companyDTO.setCompanyId("111111111111111111111111");
        // 解析表达式
        ExpressionParser expressionParser = new SpelExpressionParser();
        // 计算表达式字符串的值
        Expression expression11 = expressionParser.parseExpression("companyName");
        // 根据上下文自动对类型进行转换
        StandardEvaluationContext context11 = new StandardEvaluationContext();
        Object result = expression11.getValue(context11);
        log.info("结果:{}", JSON.toJSONString(result));*/
    }
}
